# Game.py: Alien Xenocide main module
# 04/06/09
# Copyright(c) 2009 Victor Freire e Cassio Espindola. All rights reserved.
# Python 2.6.2

import os
import sys
import pygame

import Sprites
import Gameobjects
import Timer
import Input
import Raycaster
import Maps
import Weapons
import Defines
import Menu
import Stars
import ScreenFX
import Shared
import Renderer
import Gamescript
import Sound

try:
    import psyco
    psyco.full()
except ImportError:
    print "Performance Warning: psyco not available"
    pass

class FPS_counter:
    def __init__(self):
        self.frames = 0
    def average(self):
        return self.frames / (pygame.time.get_ticks() / 1000.)


# FOR EDITING!!
class MonsterCreator:
    def __init__(self):
        self.monsters = []
        self.getsecondpoint = False
        self.p1cache = (0, 0)
        
    def addp1(self, p1):
        if self.getsecondpoint:
            self.create_str(p1)
            self.getsecondpoint = False
        else:
            self.p1cache = p1
            self.getsecondpoint = True
             
    
    def addp2(self, p2):
        if self.getsecondpoint:
            self.getsecondpoint = False
            self.create_str(self.p1cache, p2)
        else:
            print 'no p1'
    
    
    def create_str(self, p1, p2=None):
        prefix = 'soldier'
        if p2:
            x_y = zip(p1, p2)
            xdiff = abs(x_y[0][0] - x_y[0][1])
            ydiff = abs(x_y[1][0] - x_y[1][1])
            if xdiff < ydiff:
                self.monsters.append('|'.join((prefix, '%d-%d|%d-%d' % (p1[0], p1[1], p1[0], p2[1]))))
            else:
                self.monsters.append('|'.join((prefix, '%d-%d|%d-%d' % (p1[0], p1[1], p2[0], p1[1]))))
        else:
            self.monsters.append('|'.join((prefix, '%d-%d|' % p1)))
        print self.monsters[-1]
MonsterEditor = MonsterCreator()
            
            


class Game(Menu.Menu):
    def __init__(self):
        ''' Initializes the game data and modules. '''

        Sound.Sound.pre_init()       
        
        # Pygame initialization
        pygame.init()
        
        pygame.mixer.set_num_channels(32)
        pygame.mixer.music.set_volume(1.0)
        # Sound init        
        Sound.Sound.load_sounds()
#        Gamescript.SoundDirector.sound_event()
                
        # Set window caption and icon
        pygame.display.set_caption(Defines.WINDOW_TITLE)
        icon = pygame.image.load(os.path.join('data', 'sprites', 'ax.png'))
        if icon: pygame.display.set_icon(icon)
        else: warn("Failed to load window icon!")
    
        screen_flags = Defines.SCREEN_FLAGS
        if len(sys.argv) > 1 and sys.argv[1] == '-fullscreen':
            screen_flags = pygame.FULLSCREEN
        # Pygame display configuration
        try:
            self.screen = pygame.display.set_mode((Defines.SCREEN_WIDTH, Defines.SCREEN_HEIGHT), screen_flags, Defines.SCREEN_BPP)
        except pygame.error, msg:
            print "Error: failed to initialize display -", msg
                
        # Sprites Manager
        Sprites.Sprites.load_sprites()
        self.Weapons = Weapons.Weapons()
        
        # Raycasting renderer
        self.Raycaster = Raycaster.RaycasterClass(Defines.PROJECTION_WIDTH, Defines.PROJECTION_HEIGHT)
        
        # The Player
        self.player = Gameobjects.Player((Defines.MAP_START_POS_X, Defines.MAP_START_POS_Y), 45)
        
        # The Guns
        self.Weapons = Weapons.Weapons()
                
        # Setup map system(map system loads stuff automatically)
        Maps.Maps.set_current_map('map0')
        
        # Load the Menu
        Menu.Menu.__init__(self)

        self.mult_factor = 0
        self.state = [self.main_menu]
                
        #self.game_objects = [Gameobjects.Enemy('soldier', (768, 200), ((768, 200), (768, 400))),
        #                    Gameobjects.Enemy('soldier', (768, 440), ((768, 440), (1024, 440))),
        #                    Gameobjects.Enemy('soldier', (1024, 300), None),
        #                    Gameobjects.Enemy('soldier', (2688, 300), None)]
        
        Sound.Sound.play_music('menu')        
        #Gamescript.GameDirector.new_game(self.player)
        
        self.hud_font = pygame.font.SysFont('ALIEN5.TTF',26)
        self.hud_font2 = pygame.font.SysFont('ALIEN5.TTF',32)
        self.hud_deck_surface = self.hud_font.render("DECK", True, (255,255,255))
        
        self.tutorial = True
         

    def shutdown(self):
        pygame.quit()
        
    
    def new_game(self):
        Maps.Maps.maps = {}
        Maps.Maps.objects = {}
        Maps.Maps.load_maps()
        self.reset_menu()
        self.Weapons.recharge()
        self.player.health = self.player.max_health
        Gamescript.GameDirector.new_game(self.player)
        self.state.append(self.game)
        self.death_time_elapsed = 0
        self.tutorial = True
        Sprites.Sprites.get_sprite('ui\\fasttutorial').set_alpha(210)


    def game(self):
        if not self.handle_input(self.mult_factor):
            Sound.Sound.play_music('menu')
            return False
        objects = Gamescript.GameDirector.objects
        for o in objects:
            o.main(self.player, self.mult_factor, self.time_variation)

        self.screen.fill((0, 0, 0)) #clear screen
        self.Raycaster.render_scene(self.screen, self.player, objects)
        self.Weapons.draw(self.screen)
        self.draw_hud()
        
        ScreenFX.ShieldHit.main(self.screen, self.mult_factor)
        
        if self.tutorial:
            self.screen.blit(Sprites.Sprites.get_sprite('ui\\fasttutorial'), (0, 0))
        
        if self.player.health < 1:
            if not(ScreenFX.BloodDeath.finished or ScreenFX.BloodDeath.running):
                ScreenFX.BloodDeath.reset()
            
            ScreenFX.BloodDeath.update()
            ScreenFX.BloodDeath.draw(self.screen)
            
            self.death_time_elapsed += self.time_variation
            if self.death_time_elapsed > Defines.DEAD_SCREEN_TIME:
                Sound.Sound.play_music('menu')
                return False
                
        pygame.display.flip()
        return True
        
        
    def draw_hud(self):
        self.screen.blit(Sprites.Sprites.get_sprite('ui\\barra_status'), (0, Defines.SCREEN_HEIGHT - 80))
        
        self.screen.blit(self.hud_deck_surface, (570,408))
        self.screen.blit(self.hud_font2.render(str(Gamescript.GameDirector.current_map + 1), True, (255,255,255)), (587,432))
        
        shield_y = 408
        shieldbar_x = 65
        shieldbar_y = 410
        self.screen.blit(Sprites.Sprites.get_sprite('ui\\shield'), (17, shield_y))
        self.screen.fill((0,0,0), (shieldbar_x, shieldbar_y, 299, 30))
        self.screen.blit(Sprites.Sprites.get_sprite('ui\\shieldbar'), (65, shieldbar_y), (0, 0, 300 * (self.player.health / float(self.player.max_health)), 30))
        
        shellbox_y = 443
        shells_x = 65
        shells_y = 445
        shell_width = 8
        shell_proportion = 2
        self.screen.blit(Sprites.Sprites.get_sprite('ui\\shellbox'), (10, shells_y))
        self.screen.fill((0,0,0), (shells_x, shells_y+1, shell_width * (self.Weapons.current_weapon.max_ammo / shell_proportion) + 1, 29))
        shell_sprite = Sprites.Sprites.get_sprite('ui\\shotshell')
        for i in xrange(0, self.Weapons.current_weapon.ammo, 2): self.screen.blit(shell_sprite, (shells_x + ((i/shell_proportion)*8), shells_y + 2))
        
        
    def interact_map(self):
        gridposplayer = Renderer.togridF(self.player.x, self.player.y)
        for xvar in xrange(-1, 2):
            for yvar in xrange(-1, 2):
                gridpos = (gridposplayer[0] + xvar, gridposplayer[1] + yvar)
                if Maps.Maps.is_valid_grid(gridpos):
                    wid = Maps.Maps.world[gridpos[1]][gridpos[0]]
                    if wid == '0':   #empty space
                        continue
                    elif wid == 'Z': #level exit
                        Gamescript.SoundDirector.sound_event('exitdoor')
                        Gamescript.GameDirector.found_exit(self.player)
                        return
                    elif wid == 'W': #loaded recharge station
                        Maps.Maps.world[gridpos[1]][gridpos[0]] = 'X' #empty this station
                        Gamescript.SoundDirector.sound_event('recharge')
                        self.player.health = self.player.max_health
                        self.Weapons.recharge()
                        return
                                            
    def handle_input(self, mult_factor):
        keep_running = Input.Input.get_input()
        
        if Input.Input.teclas:
            self.tutorial = False
        
        if Input.Input.check_once(pygame.K_ESCAPE):
            keep_running = False
        
        
        #Is the Player alive?
        if self.player.health < 1: return keep_running
        
        mult_factor_run = mult_factor
        if Input.Input.check(pygame.K_LSHIFT):
            mult_factor *= 2  # player running?
            mult_factor_run *= 1.3  # player running?
        
        if Input.Input.check(pygame.K_UP):
            self.player.move_forward(mult_factor_run)
            
        if Input.Input.check(pygame.K_DOWN):
            self.player.move_backward(mult_factor_run)
            
        if Input.Input.check(pygame.K_LEFT):
            if Input.Input.check(pygame.K_LALT):
                self.player.strafe_left(mult_factor_run)
            else:
                self.player.turn_left(mult_factor)

        if Input.Input.check(pygame.K_RIGHT):
            if Input.Input.check(pygame.K_LALT):
                self.player.strafe_right(mult_factor_run)
            else:
                self.player.turn_right(mult_factor)
        
        if Input.Input.check(pygame.K_LCTRL):
            self.Weapons.fire(self.Raycaster.enemies_in_aim)
        
        if Input.Input.check_once(pygame.K_SPACE):
            self.interact_map()
            
        if Input.Input.check_once(pygame.K_p) and Defines.MONSTEREDIT:
            MonsterEditor.addp1((self.player.x, self.player.y))
        
        if Input.Input.check_once(pygame.K_l) and Defines.MONSTEREDIT:
            MonsterEditor.addp2((self.player.x, self.player.y))
        
        if Input.Input.check_once(pygame.K_n) and Defines.MONSTEREDIT:
            Gamescript.GameDirector.found_exit(self.player)
        
        return keep_running


def main():
    game = Game() # creates the game object and initializes the modules
    while game.state:
        game.mult_factor = Timer.Timer.get_mult_factor()
        game.time_variation = Timer.Timer.get_time_variation()
        if not game.state[-1]():
            game.state.pop()
        Timer.Timer.update()
    game.shutdown()   # cleans up before exitting
    print "Thanks for playing Alien Xenocide."    

main()
